package com.bootx.predict;

import com.bootx.predict.pojo.PredictPlugin;
import com.bootx.predict.pojo.PredictionResult;
import com.bootx.predict.pojo.RedPacketBatch;
import com.bootx.predict.pojo.RedPacketRecord;
import com.bootx.predict.util.PredictUtils;
import org.springframework.stereotype.Component;

import java.util.*;

@Component("weightedSmoothingPredict")
public class WeightedSmoothingPredict extends PredictPlugin {
    //: 0.3 ~ 0.5（越大越重视最新数据）
    private final double alpha = 0.5;
    private final int maxHistory = 20;

    @Override
    public String getName() {
        return "weightedSmoothingPredict";
    }

    @Override
    public List<PredictionResult> predict(List<RedPacketBatch> list, Set<Integer> indexes) {
        List<RedPacketRecord> history = PredictUtils.parseData(list);

        // 按index和轮次分组
        Map<Integer, Map<Long, List<RedPacketRecord>>> grouped = new HashMap<>();
        for (RedPacketRecord r : history) {
            grouped.computeIfAbsent(r.getIndex(), k -> new HashMap<>())
                    .computeIfAbsent(r.getRoundId(), k -> new ArrayList<>())
                    .add(r);
        }

        List<PredictionResult> results = new ArrayList<>();
        for (int idx : indexes) {
            Map<Long, List<RedPacketRecord>> rounds = grouped.getOrDefault(idx, Collections.emptyMap());
            if (rounds.isEmpty()) {
                results.add(new PredictionResult(idx, 0, 0, 0.5, 0));
                continue;
            }

            List<Long> sortedRounds = new ArrayList<>(rounds.keySet());
            Collections.sort(sortedRounds);
            int size = sortedRounds.size();
            int start = Math.max(0, size - maxHistory);
            List<Long> recentRounds = sortedRounds.subList(start, size);

            List<Double> ratios = new ArrayList<>();
            for (Long roundId : recentRounds) {
                List<RedPacketRecord> recs = rounds.get(roundId);
                int total = recs.size();
                int oddCount = (int) recs.stream().filter(r -> PredictUtils.isAmountOdd(r.getAmount())).count();
                ratios.add(oddCount / (double) total);
            }

            // 计算加权平均
            double weightedSum = 0;
            double weightSum = 0;
            int n = ratios.size();
            for (int i = 0; i < n; i++) {
                double w = alpha * Math.pow(1 - alpha, n - 1 - i);
                weightedSum += w * ratios.get(i);
                weightSum += w;
            }
            double predictedProb = weightedSum / weightSum;

            // 限制概率
            if (predictedProb > 0.99) {
                predictedProb = 0.99;
            }
            if (predictedProb < 0.01) {
                predictedProb = 0.01;
            }

            int total = 0, oddCount = 0;
            for (List<RedPacketRecord> recs : rounds.values()) {
                total += recs.size();
                oddCount += recs.stream().filter(r -> PredictUtils.isAmountOdd(r.getAmount())).count();
            }
            double avgOpenTime = rounds.values().stream()
                    .flatMap(Collection::stream)
                    .mapToInt(RedPacketRecord::getOpenTime)
                    .average()
                    .orElse(0);

            results.add(new PredictionResult(idx, total, oddCount, predictedProb, Double.valueOf(avgOpenTime+"").intValue()));
        }

        return results;
    }
}
